package Prototype;

/**
 * @Author: Cjj
 * 适配器模式
 * 充当两个不兼容接口之间的桥梁,属于结构设计模式。它通过一个中间件(适配器)将一个类的
 * 接口转换成客户期望的另一个接口，使原本不能一起工作的类能够协调工作。
 * 这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能
 */
public class Adapter {
    /**
     * 假设有一个音频播放器,它只能播放MP3文件。现在，我们需要播放VLC和MP4文件。
     * 目标接口：定义一个可以播放多种格式文件的音频播放器接口。
     * 适配者类：现有的音频播放器,只能播放MP3文件。
     * 适配器类：创建一个新的类,实现目标接口，并在内部使用适配者类来播放MP3文件，同时添加对VLC和MP4文件的支持。
     *
     * 概述
     *  适配器模式是一种软件设计模式,旨在解决不同接口之间的兼容性问题。
     *  目的：将一个类的接口转化为另一个接口,使得原本不兼容的类可以协同工作。
     *  主要解决的问题：在软件系统中,需要将现有的对象放入新环境,而新环境要求的接口与现有对象不匹配
     *
     *  使用场景
     *   需要使用现有类 但其接口不符合系统需求
     *   希望创建一个可复用的类 与多个不相关的类(包括未来可能引入的类)一起工作,这些类可能没有统一的接口
     *   适配器模式在Java中应用广泛，例如java.util.Arrays.asList()方法，它将数组转换为List。
     *   实现方式
     *   继承或依赖：推荐使用依赖关系,而不是继承 以保持灵活性
     *
     *   优点 促进了类之间的协同工作,即使它没有直接的关联
     *   提高了类的复用性。
     *   增加了类的透明度
     *   提供了良好的灵活性
     *
     *   缺点
     *   过度使用适配器可能导致系统结构混乱,难以理解和维护
     *   在Java中由于只能继承一个类 因此只能适配一个类,且目标类必须是抽象的
     *   使用建议
     *    适配器模式应该谨慎使用,特别是在详细设计阶段,它更多地用于解决现有系统的问题。
     *    在考虑修改一下正常运行的系统接口时,适配器模式是一个合适的选择。
     *    通过这种方式,适配器模式可以清晰地表达其核心概念和应用,同时避免不必要的复杂性
     *
     *   结构
     *    目标接口：定义客户需要的接口
     *    适配者类：定义一个已经存在的接口,这个接口需要适配。
     *    适配器类：实现目标接口,并通过组合或继承的方式调用适配者类中的方法，从而实现目标接口
     */

    public interface MediaPlayer {
        public void play(String audioType, String fileName);
    }

    public interface AdvancedMediaPlayer {
        public void playVlc(String fileName);
        public void playMp4(String fileName);
    }

    public class VlcPlayer implements AdvancedMediaPlayer {
        @Override
        public void playVlc(String fileName) {
            System.out.println("Playing vlc file. Name: "+ fileName);
        }

        @Override
        public void playMp4(String fileName) {
            //do nothing
        }
    }

    public class Mp4Player implements AdvancedMediaPlayer {
        @Override
        public void playVlc(String fileName) {
            //do nothing
        }

        @Override
        public void playMp4(String fileName) {
            System.out.println("Playing mp4 file. Name: "+ fileName);
        }
    }

    public class MediaAdapter implements MediaPlayer {
         AdvancedMediaPlayer advancedMusicPlayer;

        public MediaAdapter(String audioType) {
            if(audioType.equalsIgnoreCase("vlc")){
               advancedMusicPlayer= new VlcPlayer();
            } else if (audioType.equalsIgnoreCase("mp4")) {
                advancedMusicPlayer = new Mp4Player();
            }
        }


        @Override
        public void play(String audioType, String fileName) {
            if(audioType.equalsIgnoreCase("vlc")){
                advancedMusicPlayer.playVlc(fileName);
            }
            else if(audioType.equalsIgnoreCase("mp4")){
                advancedMusicPlayer.playMp4(fileName);
            }

    }
    public class AdapterPatternDemo{
        public static void main(String[] args) {
           Adapter adapter = new Adapter();

           adapter.play("mp4", "alone.mp4");
           adapter.play("mp3","beyond the horizon.mp3");
           adapter.play("vlc","far far away.vlc");
           adapter.play("avi","mind me.avi");
        }
        }
    }

    private void play(String mp4, String video) {
        System.out.println("Playing mp4 file. Name: " + video);
    }
}
